package com.example.excel.resolve;

import com.example.excel.annotation.helper.ExcelAnnotation;
import com.example.excel.annotation.helper.OnHandlerExcelAnnotation;
import com.example.excel.pojo.BaseRow;
import com.example.excel.pojo.BaseSheet;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class ExcelResolveAnnotationImpl extends AbsExcelResolveTemplate<Object> {


    private OnHandlerExcelAnnotation.Factory factory;

    private Set<ExcelAnnotation> annotations;
    private IntervalList<ExcelAnnotation> annotationList;

    private ExcelAnnotation tempAnnotation;
    private Map<Integer, Field> tempFieldMap;

    private ExcelResolveAnnotationImpl() {
    }

    public static <T> ExcelResolveAnnotationImpl create(Class...classes){
        ExcelResolveAnnotationImpl impl = new ExcelResolveAnnotationImpl();
        impl.factory = new OnHandlerExcelAnnotation.Factory();
        impl.factory.parseAnnotation(classes);
        return impl;
    }

    /**
     * 通过 int值 在区间数组中找到对应区间的值
     * 根据 RowNum 找到对应 【RowStart，RowEnd】的注解类解析对应行数据
     * @param <K>
     */
    private static class IntervalList<K>{

        List<int[]> intervals;
        List<K> values;

        public IntervalList() {
            intervals = new ArrayList<>();
            values = new ArrayList<>();
        }

        public void put(int start, int end, K value){
            //保证区间值是按顺序存放在数组中 [(1,5),(7,10),(12,20)...]
            int index = findIntervalIndex(start, end);
            int[] itl = new int[]{start, end};
            if(index<intervals.size()){
                intervals.add(index, itl);
                values.add(index, value);
            }else{
                intervals.add(itl);
                values.add(value);
            }
        }

        public K get(int middle){
            int index = -1;
            for (int i = 0; i < intervals.size(); i++) {
                int[] interval = intervals.get(i);
                //存放的时候，是对区间的做过从小到大排序，取的时候，
                // 如果小于区间头或者大于区间尾，那么就没有包含当前值的区间
                // [(1,5),(7,10),(12,20)...] 此时寻找 6 对应的区间 ，对比到(7,10)的位置，就可以跳出循环了
                if(middle<interval[0]){
                    break;
                }
                if(middle <= interval[1] &&  middle >= interval[0]){
                    index = i;
                    break;
                }
            }
            if(index>-1 && index<values.size()){
                return values.get(index);
            }else{
                return null;
            }
        }

        private int findIntervalIndex(int start, int end){
            if(start>end){
                throw new IllegalArgumentException("区间数值["+start+","+end +"] start 不能大于 end ");
            }
            for (int i = 0; i < intervals.size(); i++) {
                int[] interval = intervals.get(i);
                if(end <= interval[0]){
                    return i;
                }
            }
            return intervals.size();
        }

        public void clear() {
            intervals.clear();
            values.clear();
        }
    }

    @Override
    public boolean isResolveSheet(BaseSheet<Object> baseSheet) {
        annotations = factory.getReadSheetClass(baseSheet.getSheetIndex(), baseSheet.getSheetName());
        if(annotations!=null && annotations.size()>0){
            annotationList = new IntervalList<>();
            for (ExcelAnnotation annotation : annotations) {
                annotationList.put(annotation.getStartRow(), annotation.getEndRow(), annotation);
            }
            return true;
        }
        return false;
    }

    @Override
    public boolean isResolveRow(int rowNum, Row row) {
        tempAnnotation = annotationList.get(rowNum);
        if(tempAnnotation!=null){
            tempFieldMap = tempAnnotation.getColumns();
            return true;
        }
        return false;
    }

    @Override
    Object newInstanceRow(BaseRow<Object> baseRow, Row row) {
        Object obj = null;
        try {
            obj = tempAnnotation.getaClass().newInstance();
        }catch (Exception e){
            e.printStackTrace();
        }
        return obj;
    }


    @Override
    void resolveCell(BaseRow<Object> baseRow, int cellNum, Cell cell, Object data) {
        if(data!=null && tempFieldMap!=null){
            parseCell(cell, tempFieldMap.get(cellNum), data);
        }
    }

    @Override
    public void clear() {
        super.clear();
        annotations.clear();
        annotationList.clear();
        tempAnnotation = null;
        tempFieldMap.clear();
    }

    private void parseCell(Cell cell, Field field, Object o) {
        field.setAccessible(true);
        try {
            field.set(o, formatValue(cell, field.getType()));
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}
